package com.cdzs.twocamera;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Handler;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.ImageView;

import com.cdzs.twocamera.constant.Constant;
import com.cdzs.twocamera.myinterface.NettyListener;
import com.cdzs.twocamera.tcp.NettyClient;
import com.cdzs.twocamera.util.ArrayMergeUtil;
import com.cdzs.twocamera.util.ByteUtil;
import com.cdzs.twocamera.util.DateFormatUtil;
import com.cdzs.twocamera.util.NumberUtil;
import com.cdzs.twocamera.util.TcpAssembleUtil;
import com.cdzs.twocamera.util.WriteLogUtil;

import java.io.ByteArrayOutputStream;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import timber.log.Timber;

public class NettyActivity extends AppCompatActivity implements NettyListener {

    private static final String TAG = "NettyActivity";

    private NetworkReceiver receiver;

    private final Timer timer = new Timer();

    private ScheduledExecutorService mScheduledExecutorServiceForHeartbeat;
    private byte[] heartBeatBytes;
    private byte[] picDataBytes;
    private ImageView imageView;
    private int personIdIndex;
    private int personNameIndex;
    private int dataLength = 0;
    private int totalLength = 0;
    private byte[] data = new byte[0];
    private Handler handler = new Handler();
    private Bitmap bitmap;
    private Bitmap bmp;
    private int overFlowCount;
    private int stickPackageIndex;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_netty);

        imageView = findViewById(R.id.imageView);

        receiver = new NetworkReceiver();
        IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
        LocalBroadcastManager.getInstance(this).registerReceiver(receiver, filter);

        NettyClient.getInstance().setListener(this);

        connect();

        // 自定义心跳，每隔20秒向服务器发送心跳包
        mScheduledExecutorServiceForHeartbeat = Executors.newSingleThreadScheduledExecutor();


        // 线程池中发心跳包
        mScheduledExecutorServiceForHeartbeat.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {

                heartBeatBytes = ArrayMergeUtil.byteMergerAll(
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.NET_HEADER_DATA)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(16)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.HEART_BEAT_PACKAGE_TYPE)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.HEART_BEAT_PACKAGE_DATA)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.HEART_BEAT_PACKAGE_DATA)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.HEART_BEAT_PACKAGE_DATA)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.HEART_BEAT_PACKAGE_DATA)).order(ByteOrder.LITTLE_ENDIAN).getInt())
                );

                NettyClient.getInstance().sendMsgToServer(heartBeatBytes, new ChannelFutureListener() {    //3
                    @Override
                    public void operationComplete(ChannelFuture future) {
                        if (future.isSuccess()) {                //4
                            Timber.d("Write heartbeat successful");

                        } else {
                            Timber.e("Write heartbeat error");
                            WriteLogUtil.writeLogByThread("heartbeat error");
                        }
                    }
                });
            }
        }, 3, 3, TimeUnit.SECONDS);

        sendPicDataPackage();
    }


    /**
     * 发送图片数据包
     */
    public void sendPicDataPackage() {

        timer.schedule(new TimerTask() {
            @Override
            public void run() {

                picDataBytes = ArrayMergeUtil.byteMergerAll(

                        // 以下三条为请求头部分
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.NET_HEADER_DATA)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                        // 表示数据包的长度，只是数据，不包含头
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(picToByte().length + 916)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                        // 数据包的类型 0x30
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.DATA_PACKAGE_TYPE)).order(ByteOrder.LITTLE_ENDIAN).getInt()),

                        //============================================ 以下为真正的数据包 =================================================================
                        // 标识请求的哪一个比对服务
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.ENUM_TYPE)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                        // 64 字节key，确保请求的唯一性
                        TcpAssembleUtil.assembleRequestKey(),
                        //  20个字节的0
                        TcpAssembleUtil.assembleRequestId(),
                        // 请求优先级,
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.REQUEST_PRIORITY)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                        // 阈值
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.REQUEST_THRESHOLD)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                        // 最大结果数
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.REQUEST_TOP_X)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                        // 图片的张数
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.REQUEST_PIC_NUM)).order(ByteOrder.LITTLE_ENDIAN).getInt()),

                        // 现场图片的长度，需动态计算
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(picToByte().length)).order(ByteOrder.LITTLE_ENDIAN).getInt()),
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(0)).order(ByteOrder.LITTLE_ENDIAN).getInt()),

                        // 有几张脸，暂时为 0
                        NumberUtil.getByteArray(ByteBuffer.wrap(NumberUtil.getByteArray(Constant.REQUEST_FACE_COUNT)).order(ByteOrder.LITTLE_ENDIAN).getInt()),

                        // 50结构体，每个结构体有4个int
                        TcpAssembleUtil.assembleStruct(),

                        // 图片数据
                        picToByte()
                );

                Log.d(TAG, "run: 图片发送时间" + DateFormatUtil.format(System.currentTimeMillis(), DateFormatUtil.DateFormatEnum.ymdhmss));

                Log.d(TAG, "sendPicDataPackage: 发送的数据长度" + picDataBytes.length);

                NettyClient.getInstance().sendMsgToServer(picDataBytes, new ChannelFutureListener() {    //3
                    @Override
                    public void operationComplete(ChannelFuture future) {
                        if (future.isSuccess()) {                //4
                            Timber.d("Write heartbeat successful");

                        } else {
                            Timber.e("Write heartbeat error");
                            WriteLogUtil.writeLogByThread("heartbeat error");
                        }
                    }
                });
            }
        }, 0, 500);
    }


    /**
     * 获取图片对应的字节数组
     *
     * @return
     */
    public byte[] picToByte() {
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pic);
        // 图片压缩为 JPEG
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 20, baos);
//        bmp = BitmapFactory.decodeByteArray(baos.toByteArray(), 0, baos.toByteArray().length);
//        Log.d(TAG, "picToByte: 图片长度   " + baos.toByteArray().length);
//
//        // 抛到UI线程去执行
//        handler.post(new Runnable() {
//            @Override
//            public void run() {
//                imageView.setImageBitmap(bmp);
//            }
//        });

        return baos.toByteArray();
    }


    @Override
    protected void onStart() {
        super.onStart();
    }

    private void connect() {
        if (!NettyClient.getInstance().getConnectStatus()) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    //连接服务器
                    NettyClient.getInstance().connect();
                }
            }).start();
        }
    }

    // 关闭线程池
    private void shutdown() {
        if (mScheduledExecutorServiceForHeartbeat != null) {
            mScheduledExecutorServiceForHeartbeat.shutdown();
            mScheduledExecutorServiceForHeartbeat = null;
        }
    }

    /**
     * 接收服务器的消息
     *
     * @param byteBuf
     */
    @Override
    public void onMessageResponse(ByteBuf byteBuf) {

        Log.d(TAG, "run: 收到服务器数据时间：" + DateFormatUtil.format(System.currentTimeMillis(), DateFormatUtil.DateFormatEnum.ymdhmss));

        byte[] bytes = byteBuf.array();

        // data.length 原有数据长度，bytes.length 新增数据长度
        byte[] temp = new byte[data.length + byteBuf.readableBytes()];
        // 先将原有数据复制到 中间数组中
        System.arraycopy(data, 0, temp, 0, data.length);
        // 在将新增的数据复制到中间数据中
        System.arraycopy(bytes, 0, temp, data.length, byteBuf.readableBytes());
        // 最终得到数据数组
        data = temp;

        if (data.length > 28) {

            Log.d(TAG, "data长度: " + data.length);
            Log.d(TAG, "数据头: " + "0x" + Integer.toHexString(ByteBuffer.wrap(ByteUtil.subBytes(data, 0, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt()));
            Log.d(TAG, "数据类型: " + "0x" + Integer.toHexString(ByteBuffer.wrap(ByteUtil.subBytes(data, 8, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt()));


            if (0x55AA55AA == ByteBuffer.wrap(NumberUtil.getByteArray(NumberUtil.getInt(data, 0))).order(ByteOrder.LITTLE_ENDIAN).getInt() &&
                    1 == ByteBuffer.wrap(NumberUtil.getByteArray(NumberUtil.getInt(data, 8))).order(ByteOrder.LITTLE_ENDIAN).getInt()) {

                Log.d(TAG, "onMessageResponse: 收到心跳包 > 28");
                Log.d(TAG, "run: 心跳包接收时间 > 28" + DateFormatUtil.format(System.currentTimeMillis(), DateFormatUtil.DateFormatEnum.ymdhmss));

                data = ByteUtil.subBytes(data, 28, data.length - 28);

            } else if (0x55AA55AA == ByteBuffer.wrap(NumberUtil.getByteArray(NumberUtil.getInt(data, 0))).order(ByteOrder.LITTLE_ENDIAN).getInt() &&
                    0x30 == ByteBuffer.wrap(NumberUtil.getByteArray(NumberUtil.getInt(data, 8))).order(ByteOrder.LITTLE_ENDIAN).getInt()) {
                Log.d(TAG, "onMessageResponse: 收到数据包");
                Log.d(TAG, "run: 数据包接收时间" + DateFormatUtil.format(System.currentTimeMillis(), DateFormatUtil.DateFormatEnum.ymdhmss));

                dataLength = ByteBuffer.wrap(ByteUtil.subBytes(data, 4, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt();
                Log.d(TAG, "数据包长度: " + (dataLength + 12));

                // 当数据长度或等于一个数据包的长度时，才截断出一个完整的数据包
                if (data.length >= dataLength + 12) {
                    //图片字节长度
                    int picLength = ByteBuffer.wrap(ByteUtil.subBytes(data, 348, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt();

                    byte[] picByte = ByteUtil.subBytes(data, 352, picLength);

                    bitmap = BitmapFactory.decodeByteArray(picByte, 0, picByte.length);
                    // 抛到UI线程去执行
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            imageView.setImageBitmap(bitmap);
                        }
                    });
                    Log.d(TAG, "onMessageResponse:收到数据包长度 " + data.length);
                    Log.d(TAG, "onMessageResponse 请求头: " + "0x" + Integer.toHexString(ByteBuffer.wrap(ByteUtil.subBytes(data, 0, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt()));
                    Log.d(TAG, "onMessageResponse: 拼接数据长度 if " + data.length);
                    Log.d(TAG, "onMessageResponse 数据长度: " + ByteBuffer.wrap(ByteUtil.subBytes(data, 4, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt());
                    Log.d(TAG, "onMessageResponse 请求类型: " + "0x" + Integer.toHexString(ByteBuffer.wrap(ByteUtil.subBytes(data, 8, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt()));
                    Log.d(TAG, "onMessageResponse 请求 enumType: " + ByteBuffer.wrap(ByteUtil.subBytes(data, 12, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt());
                    Log.d(TAG, "onMessageResponse 请求头 key: " + ByteBuffer.wrap(ByteUtil.subBytes(data, 16, 64)).order(ByteOrder.LITTLE_ENDIAN).getInt());
                    Log.d(TAG, "onMessageResponse 请求头结果，“0”代表验证失败,“1”代表验证成功 : " + ByteBuffer.wrap(ByteUtil.subBytes(data, 80, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt());
                    Log.d(TAG, "onMessageResponse 比对分数 : " + ByteBuffer.wrap(ByteUtil.subBytes(data, 84, 4)).order(ByteOrder.LITTLE_ENDIAN).getFloat());
                    Log.d(TAG, "onMessageResponse 结果数目 : " + ByteBuffer.wrap(ByteUtil.subBytes(data, 88, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt());

                    // 截取人员 ID
                    byte[] personIDByte = ByteUtil.subBytes(data, 92, 20);
                    for (int i = 0; i < personIDByte.length; i++) {
                        if (personIDByte[i] == 0) {
                            personIdIndex = i;
                            break;
                        }
                    }
                    Log.d(TAG, "onMessageResponse:人员ID " + new String(ByteUtil.subBytes(personIDByte, 0, personIdIndex)));

                    // 截取人员 姓名
                    byte[] personNameByte = ByteUtil.subBytes(data, 112, 40);
                    for (int i = 0; i < personNameByte.length; i++) {
                        if (personNameByte[i] == 0) {
                            personNameIndex = i;
                            break;
                        }
                    }
                    Log.d(TAG, "onMessageResponse 人员姓名 : " + new String(ByteUtil.subBytes(personNameByte, 0, personNameIndex)));

                    // 时间
                    BigInteger bigInteger = new BigInteger(ByteUtil.subBytes(data, 152, 64));
                    long longValue = bigInteger.longValue();
                    Log.d(TAG, "onMessageResponse 时间: " + DateFormatUtil.format(longValue, DateFormatUtil.DateFormatEnum.ymdhms));
                    Log.d(TAG, "onMessageResponse 点位 : " + ByteUtil.subBytes(data, 216, 128));
                    Log.d(TAG, "onMessageResponse 比对分数 : " + ByteBuffer.wrap(ByteUtil.subBytes(data, 344, 4)).order(ByteOrder.LITTLE_ENDIAN).getFloat());
                    Log.d(TAG, "onMessageResponse 注册图片长度 : " + ByteBuffer.wrap(ByteUtil.subBytes(data, 348, 4)).order(ByteOrder.LITTLE_ENDIAN).getInt());

                    data = ByteUtil.subBytes(data, dataLength + 12, data.length - dataLength - 12);
                }
            }
        } else if (data.length == 28) {
            if (0x55AA55AA == ByteBuffer.wrap(NumberUtil.getByteArray(NumberUtil.getInt(data, 0))).order(ByteOrder.LITTLE_ENDIAN).getInt() &&
                    0x1 == ByteBuffer.wrap(NumberUtil.getByteArray(NumberUtil.getInt(data, 8))).order(ByteOrder.LITTLE_ENDIAN).getInt()) {

                Log.d(TAG, "onMessageResponse: 收到心跳包 == 28");
                Log.d(TAG, "run: 心跳包接收时间 == 28" + DateFormatUtil.format(System.currentTimeMillis(), DateFormatUtil.DateFormatEnum.ymdhmss));

                // 数据长度刚好等于28，如果是心跳包，接收完成后，直接丢弃
                data = new byte[0];
            }
        }
    }


    /**
     * 和服务器的连接状态发生改变
     *
     * @param statusCode
     */
    @Override
    public void onServiceStatusConnectChanged(int statusCode) {
        Timber.d("connect status:%d", statusCode);
        if (statusCode == NettyListener.STATUS_CONNECT_SUCCESS) {
            //authenticData();
            // 连接成功

        } else if (statusCode == NettyListener.STATUS_CONNECT_CLOSED) {
            // 连接关闭
        } else if (statusCode == NettyListener.STATUS_CONNECT_ERROR) {
            // 连接出错
            WriteLogUtil.writeLogByThread("tcp connect error");
        }
    }

    public class NetworkReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
            if (activeNetwork != null) { // connected to the internet
                if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI || activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE) {
                    connect();
                }
            }
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
        shutdown();
        NettyClient.getInstance().setReconnectNum(0);
        NettyClient.getInstance().disconnect();
    }
}
